const gulp = require('gulp')
// gulp core function
const { src, dest, series, parallel, watch } = require('gulp')
// gulp compress js
const uglify = require('gulp-uglify')
// gulp judgment
const gulpif = require('gulp-if')
// gulp compress css
const cleanCSS = require('gulp-clean-css')
// Delete Files
const del = require('delete')
// Refresh the browser in real time
const browserSync = require('browser-sync').create()
const reload = browserSync.reload
// proxy
const { createProxyMiddleware } = require('http-proxy-middleware')
// According to html reference, files are merged
// const useref = require('gulp-useref');
// File merge
const concat = require('gulp-concat')
// rollup packaging, processing es6 modules
const { rollup } = require('rollup')
// rollup looks for node_modules module
const { nodeResolve } = require('@rollup/plugin-node-resolve')
// rollup converts commonjs module to es6 module
const commonjs = require('@rollup/plugin-commonjs')
// rollup code compression
const terser = require('rollup-plugin-terser').terser
// rollup babel plugin, support the latest ES grammar
const babel = require('@rollup/plugin-babel').default
// const gulpBabel = require('gulp-babel');
// Distinguish development and production environments
const production = process.env.NODE_ENV === 'production' ? true : false

const pkg = require('./package.json')
const banner = `/*! @preserve
 * ${pkg.name}
 * version: ${pkg.version}
 */`

const uglifyOptions = {
  compress: {
    drop_console: true,
  },
}

// babel config
const babelConfig = {
  compact: false,
  babelHelpers: 'bundled',
  exclude: 'node_modules/**', // Only compile our source code
  plugins: [],
  presets: [
    [
      '@babel/preset-env',
      {
        useBuiltIns: 'usage',
        corejs: 3,
        targets: {
          chrome: 58,
          ie: 11,
        },
      },
    ],
  ],
}

// file handler paths
const paths = {
  // static resources,contains index.html, fonts and images,and extension plugins dependency
  staticHtml: ['src/*.html'],
  staticFonts: ['src/fonts/**'],
  staticAssets: ['src/assets/**'],
  staticImages: ['src/plugins/images/*.png', 'src/plugins/images/*.gif'],
  staticExpendPlugins: [
    'src/expendPlugins/**',
    '!src/expendPlugins/**/plugin.js',
  ],
  staticDemoData: ['src/demoData/*.js'],
  staticCssImages: ['src/css/**', '!src/css/*.css'],

  // static resources dest
  destStaticHtml: ['dist'],
  destStaticFonts: ['dist/fonts'],
  destStaticAssets: ['dist/assets'],
  destStaticImages: ['dist/plugins/images'],
  destStaticExpendPlugins: ['dist/expendPlugins'],
  destStaticDemoData: ['dist/demoData'],
  destStaticCssImages: ['dist/css'],

  //core es module
  core: [
    'src/**/*.js',
    '!src/demoData/*.js',
    'src/expendPlugins/**/plugin.js',
    '!src/plugins/js/*.js',
  ],

  //plugins src
  pluginsCss: ['src/plugins/css/*.css'],
  plugins: ['src/plugins/*.css'],
  css: [
    'src/css/*.css',
    'node_modules/flatpickr/dist/themes/light.css',
    'src/plugins/css/zTree/zTreeStyle/zTreeStyle.css',
  ],
  pluginsJs: [
    'node_modules/jquery/dist/jquery.min.js',
    'node_modules/uuid/dist/umd/uuid.min.js',
    'src/plugins/js/clipboard.min.js',
    'src/plugins/js/spectrum.min.js',
    'src/plugins/js/jquery-ui.min.js',
    'src/plugins/js/jquery.mousewheel.min.js',
    // 'src/plugins/js/numeral.min.js',
    'src/plugins/js/html2canvas.min.js',
    'src/plugins/js/localforage.min.js',
    'src/plugins/js/lodash.min.js',
    'src/plugins/js/jstat.min.js',
    'src/plugins/js/crypto-api.min.js',
    'src/plugins/js/jquery.sPage.min.js',
    'src/plugins/js/datatables.js',
    'src/plugins/js/pako_deflate.min.js',
    'src/plugins/js/zTree/jquery.ztree.all.min.js',
    'src/plugins/js/zTree/jquery.ztree.core.min.js',
    'src/plugins/js/zTree/jquery.ztree.exedit.min.js',
  ],

  //plugins concat
  concatPluginsCss: 'pluginsCss.css',
  concatPlugins: 'plugins.css',
  concatCss: 'luckysheet.css',
  concatPluginsJs: 'plugin.js',

  //plugins dest
  destPluginsCss: ['dist/plugins/css'],
  destPlugins: ['dist/plugins'],
  destCss: ['dist/css'],
  destPluginsJs: ['dist/plugins/js'],

  // Package directory
  dist: 'dist',
}

// Clear the dist directory
function clean() {
  return del([paths.dist])
}

// proxy middleware
const apiProxy = createProxyMiddleware('/luckysheet/', {
  target: 'http://luckysheet.lashuju.com/', // set your server address
  changeOrigin: true, // for vhosted sites
  ws: true, // proxy websockets
})

// Static server
function serve(done) {
  browserSync.init(
    {
      server: {
        baseDir: paths.dist,
        middleware: [apiProxy], //proxy
      },
      ghostMode: false, //默认true，滚动和表单在任何设备上输入将被镜像到所有设备里，会影响本地的协同编辑消息，故关闭
    },
    done
  )
}

// Monitoring file changes
function watcher(done) {
  watch(paths.core, { delay: 500 }, series(core, reloadBrowser))

  // watch plugins and css
  watch(paths.pluginsCss, { delay: 500 }, series(pluginsCss, reloadBrowser))
  watch(paths.plugins, { delay: 500 }, series(plugins, reloadBrowser))
  watch(paths.css, { delay: 500 }, series(css, reloadBrowser))
  watch(paths.pluginsJs, { delay: 500 }, series(pluginsJs, reloadBrowser))

  // watch static
  watch(paths.staticHtml, { delay: 500 }, series(copyStaticHtml, reloadBrowser))
  watch(
    paths.staticFonts,
    { delay: 500 },
    series(copyStaticFonts, reloadBrowser)
  )
  watch(
    paths.staticAssets,
    { delay: 500 },
    series(copyStaticAssets, reloadBrowser)
  )
  watch(
    paths.staticImages,
    { delay: 500 },
    series(copyStaticImages, reloadBrowser)
  )
  watch(
    paths.staticExpendPlugins,
    { delay: 500 },
    series(copyStaticExpendPlugins, reloadBrowser)
  )
  watch(
    paths.staticDemoData,
    { delay: 500 },
    series(copyStaticDemoData, reloadBrowser)
  )
  watch(
    paths.staticCssImages,
    { delay: 500 },
    series(copyStaticCssImages, reloadBrowser)
  )

  done()
}

// Refresh browser
function reloadBrowser(done) {
  reload()

  done()
}

//Package the core code
async function core_rollup() {
  const bundle = await rollup({
    input: 'src/index.js',
    plugins: [
      nodeResolve(), // tells Rollup how to find date-fns in node_modules
      commonjs(), // converts date-fns to ES modules
      // postcss({
      // 	plugins: [],
      // 	extract: true,
      // 	// minimize: isProductionEnv,
      // }),
      production && terser(), // minify, but only in production
      babel(babelConfig),
    ],
  })

  bundle.write({
    file: 'dist/luckysheet.umd.js',
    format: 'umd',
    name: 'luckysheet',
    sourcemap: true,
    inlineDynamicImports: true,
    banner: banner,
  })

  if (production) {
    bundle.write({
      file: 'dist/luckysheet.esm.js',
      format: 'esm',
      name: 'luckysheet',
      sourcemap: true,
      inlineDynamicImports: true,
      banner: banner,
    })
  }
}

async function core() {
  await require('esbuild').buildSync({
    format: 'iife',
    globalName: 'luckysheet',
    entryPoints: ['src/index.js'],
    bundle: true,
    minify: production,
    banner: { js: banner },
    target: ['es2015'],
    sourcemap: true,
    outfile: 'dist/luckysheet.umd.js',
    logLevel: 'error',
  })
}

// According to the build tag in html, package js and css
function pluginsCss() {
  return src(paths.pluginsCss)
    .pipe(concat(paths.concatPluginsCss))
    .pipe(gulpif(production, cleanCSS()))
    .pipe(dest(paths.destPluginsCss))
}

function plugins() {
  return src(paths.plugins)
    .pipe(concat(paths.concatPlugins))
    .pipe(gulpif(production, cleanCSS()))
    .pipe(dest(paths.destPlugins))
}

function css() {
  return src(paths.css)
    .pipe(concat(paths.concatCss))
    .pipe(gulpif(production, cleanCSS()))
    .pipe(dest(paths.destCss))
}

function pluginsJs() {
  return src(paths.pluginsJs)
    .pipe(concat(paths.concatPluginsJs))
    .pipe(gulpif(production, uglify(uglifyOptions)))
    .pipe(dest(paths.destPluginsJs))
}

// Copy static resources
function copyStaticHtml() {
  return src(paths.staticHtml).pipe(dest(paths.destStaticHtml))
}
function copyStaticFonts() {
  return src(paths.staticFonts).pipe(dest(paths.destStaticFonts))
}
function copyStaticAssets() {
  return src(paths.staticAssets).pipe(dest(paths.destStaticAssets))
}
function copyStaticImages() {
  return src(paths.staticImages).pipe(dest(paths.destStaticImages))
}
function copyStaticExpendPlugins() {
  return src(paths.staticExpendPlugins).pipe(
    dest(paths.destStaticExpendPlugins)
  )
}
function copyStaticDemoData() {
  return src(paths.staticDemoData).pipe(dest(paths.destStaticDemoData))
  // .pipe(gulpBabel({
  //     presets: ['@babel/env']
  // }))
  // .pipe(gulp.dest('dist'));
}
function copyStaticCssImages() {
  return src(paths.staticCssImages).pipe(dest(paths.destStaticCssImages))
}

const dev = series(
  clean,
  parallel(
    pluginsCss,
    plugins,
    css,
    pluginsJs,
    copyStaticHtml,
    copyStaticFonts,
    copyStaticAssets,
    copyStaticImages,
    copyStaticExpendPlugins,
    copyStaticDemoData,
    copyStaticCssImages,
    core
  ),
  watcher,
  serve
)
const build = series(
  clean,
  parallel(
    pluginsCss,
    plugins,
    css,
    pluginsJs,
    copyStaticHtml,
    copyStaticFonts,
    copyStaticAssets,
    copyStaticImages,
    copyStaticExpendPlugins,
    copyStaticDemoData,
    copyStaticCssImages,
    core
  )
)

exports.dev = dev
exports.build = build
exports.default = dev
